//
// RS Game Framework
// Copyright © 2010 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//

#ifndef RS_GRAPHICS_RENDERER_HPP
#define RS_GRAPHICS_RENDERER_HPP

#include "rs/graphics/GraphicsForwards.hpp"
#include "rs/graphics/Buffer.hpp"
#include "rs/graphics/Shader.hpp"
#include "rs/graphics/Texture2D.hpp"
#include "rs/graphics/VertexFormat.hpp"
#include "rs/graphics/opengl/OpenGLForwards.hpp"
#include "rs/reflection/Reflection.hpp"
#include "rs/ReferenceCounted.hpp"
#include <vector>

namespace rs
{
    namespace graphics
    {
        namespace internal
        {
            struct Stream
            {
                std::vector< InputElement > attributes;
                BufferPtr vertexBuffer;
                UIntPtr offset;
            };
        }
        
        typedef Int32 VertexFormatID;  
        class Renderer : public ReferenceCounted
        {
            RS_DECLARE_POLYMORPHIC_REFLECTION();
            
        protected:
            
            typedef std::vector< VertexFormat > VertexFormatContainer;
            
        public:
            
            Renderer();
             
            virtual void Apply() = 0; 
            
            virtual void ApplyInputAssemberState() = 0;
            
            virtual void ApplyShaderState() = 0;

			virtual void ApplyTextures() = 0;
            
            virtual VertexFormatID CreateVertexFormat(InputElement const* inputElements, RsSize count) = 0;
            
            virtual BufferPtr CreateBuffer(BufferDescription const& desciption, void const* data) = 0;
                        
            virtual ShaderPtr CreateShader(ShaderDescription const& desciption) = 0;

			virtual Texture2DPtr CreateTexture2D(Texture2DDescription const& description) = 0;

			virtual Texture2DPtr CreateTexture2D(Texture2DDescription const& description, void const* data) = 0;
            
            virtual void Draw(UInt32 startVertexLocation, UInt32 verticeCount) = 0;
            
            virtual void DrawIndexed(UInt32 startIndexLocation, UInt32 indiceCount) = 0;
            
            virtual PrimitiveTopology::Enum GetPrimitiveTopology() const = 0;
            
            virtual void SetPrimitiveTopology(PrimitiveTopology::Enum topology) = 0;
            
            virtual void SetIndexBuffer(BufferPtr const& indexBuffer) = 0;
            
            virtual void SetShader(ShaderPtr const& shader) = 0;

			virtual void SetTexture(Char const* name, Texture2DPtr const& texture) = 0;
            
            virtual void SetVertexBuffer(BufferPtr const& vertexBuffer, UInt32 const stream = 0, UIntPtr const offset = 0) = 0;
            
            virtual void SetVertexFormat(VertexFormatID vertexFormat, ShaderPtr const& shader) = 0;
                        
        protected:
            enum { kMaxStreams = 8 };
			enum { kTextureUnits = 16 };
            
            // Resources created by the renderer, and thus owned by the renderer
            VertexFormatContainer vertexFormats_;
            
            // State data
            internal::Stream streams_[kMaxStreams];
            BufferPtr currentIndexBuffer_;
            BufferPtr currentVertexBuffer_;
            VertexFormatID currentVertexFormat_;
            ShaderPtr currentShader_;
            ShaderPtr newShader_;
			Texture2DPtr currentTextures_[kTextureUnits];
			Texture2DPtr newTextures_[kTextureUnits];
        };
        
        
        inline Renderer::Renderer()
        : currentVertexFormat_(-1) {
        }       
    }
}

#endif // RS_GRAPHICS_RENDERER_HPP